1. Field of Invention
The present invention relates generally to computing systems which include virtual machines. More particularly, the present invention relates to increasing efficiency associated with virtual machines or, more specifically, bytecode interpreters associated with virtual machines.
2. Description of the Related Art
A typical implementation of the JAVA programming language, developed by Sun Microsystems, Inc., of Palo Alto, Calif., is a JAVA programming language virtual machine which contains a bytecode interpreter. A bytecode interpreter, as will be understood by those skilled in the art is typically written in a low-level programming language, e.g., the C programming language, and executes a stack-based intermediate representation of the JAVA programming. The stack-based intermediate representation of the JAVA programming language is called Java bytecodes.
During the course of execution, a virtual machine may use C recursion in a variety of different situations. By way of example, C recursion may occur when a virtual machine re-enters an interpreter loop. A virtual machine may re-enter an interpreter loop such as a JAVA programming language bytecode interpreter loop during the execution of “<clinit>” methods, the execution of method invocation methods, and the execution of constructor methods which initiate new instances of an object. “<clinit>” methods are associated with static initializers used to create memory locations to hold static variables, while method invocation methods, e.g., a Method.invoke( ) method, may invoke methods using reflection, and constructor methods, e.g., a Constructor.newInstance( ) method, may be called the constructor method of a newly instantiated object.
When “<clinit>” methods are executed, an interpreter loop typically calls a native function written in the C programming language, i.e., a native C function, that performs various operations. The operations generally include synchronizing on a class object that represents the class or interface to be initialized using locks, as will be appreciated by those skilled in the art. The operations also generally include waiting on the class object if necessary until it becomes available, and making a recursive request for initialization if needed. In the event that initialization is not possible, the operations include throwing an error. If initialization is possible, the operations may include making a record that indicates that initialization of the class object is in progress. A determination of whether the class object represents a class rather than an interface may also be included in the operation, and if the direct superclass of this class has not yet been initialized, the uninitialized superclass is recursively initialized.
The native C function also performs a lookup for the “<clinit>” method for the class that requires initialization or its static variables, and recursively calls back into the interpreter loop to execute the identified “<clinit>” method. The native C function executes the identified “<clinit>” method of the class, and if the execution of the “<clinit>” method completes normally, then the class object is unlocked. If the execution does not complete as expected, an exception has generally either been created or thrown, and the class object may locked and labeled as erroneous. When the native C function calls back into the interpreter loop to execute a “<clinit>” method, C recursion generally occurs.
C recursion also occurs in an interpreter loop that is associated with calling a Method.invoke( ) method. When a Method.invoke( ) method is called, JAVA programming language frame on a stack may be set up with the arguments for the method that is to be called, and a lookup may be performed to identify the appropriate method to invoke. Then, an interpreter loop may be called to execute the method. In general, when the interpreter loop is called to execute the method, C recursion occurs. After the method is executed, as will be understood by those skilled in the art, cleanup and result handling may be performed.
As mentioned above, calling a Constructor.newInstance( ) method generally requires C recursion in the interpreter loop in order to invoke the constructor method of the object instantiated by the Constructor.newInstance( ) method. When a Constructor.newInstance( ) method is called, a JAVA programming language frame with the arguments for the constructor may be set up, and a lookup may be performed to identify a suitable constructor. An interpreter loop is then typically called to execute the constructor, causing C recursion to occur. After the constructor is executed, cleanup and result handling may be performed.
C recursion is often problematic for a virtual machine, as will be appreciated by those skilled in the art. By way of example, it is generally difficult to efficiently detect C stack overflow. In addition, it may also be difficult to expand an associated C stack. The difficulty associated with expanding a C stack includes the fact that expanding a C stack generally requires machine specific code.
Therefore, it would be desirable to reduce the amount of C recursion which occurs with respect to an interpreter. More particularly, what is needed is a method and an apparatus for replacing C recursion with JAVA programming language recursion in a JAVA programming language bytecode interpreter.